package com.ev.hr.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ev.apis.model.DsResultResponse;
import com.ev.common.enums.ApplyStatusDict;
import com.ev.custom.domain.UserAssocDO;
import com.ev.custom.service.DingdingService;
import com.ev.custom.service.NoticeService;
import com.ev.custom.service.UserAssocService;
import com.ev.framework.config.ConstantForHr;
import com.ev.framework.il8n.MessageSourceHandler;
import com.ev.framework.utils.DateFormatUtil;
import com.ev.framework.utils.R;
import com.ev.framework.utils.ShiroUtils;
import com.ev.framework.utils.StringUtils;
import com.ev.hr.dao.AdvertiseInfoDao;
import com.ev.hr.domain.AdvertiseInfoDO;
import com.ev.hr.domain.CandidateInfoDO;
import com.ev.hr.domain.EmployeeInfoDO;
import com.ev.hr.enums.EmployeeStateDict;
import com.ev.hr.service.AdvertiseInfoService;
import com.ev.hr.service.CandidateInfoService;
import com.ev.hr.service.EmployeeInfoService;
import com.ev.hr.vo.AdvertiseApproveParam;
import com.ev.hr.vo.AdvertiseInfoPageParam;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class AdvertiseInfoServiceImpl implements AdvertiseInfoService {
    @Autowired
    private AdvertiseInfoDao advertiseInfoDao;
    @Autowired
    private DingdingService dingdingService;
    @Autowired
    private MessageSourceHandler messageSourceHandler;
    @Autowired
    private EmployeeInfoService employeeInfoService;
    @Autowired
    private UserAssocService userAssocService;
    @Autowired
    private NoticeService noticeService;

    @Autowired
    private CandidateInfoService candidateInfoService;

    @Override
    public AdvertiseInfoDO get(Long id) {
        return advertiseInfoDao.get(id);
    }

    @Override
    public List<AdvertiseInfoDO> list(Map<String, Object> map) {
        return advertiseInfoDao.list(map);
    }

    @Override
    public int count(Map<String, Object> map) {
        return advertiseInfoDao.count(map);
    }

    @Override
    public int save(AdvertiseInfoDO advertiseInfo) {
        return advertiseInfoDao.save(advertiseInfo);
    }

    @Override
    public int update(AdvertiseInfoDO advertiseInfo) {
        return advertiseInfoDao.update(advertiseInfo);
    }

    @Override
    public int updateAll(AdvertiseInfoDO advertiseInfo) {
        return advertiseInfoDao.updateAll(advertiseInfo);
    }

    @Override
    public int remove(Long id) {
        return advertiseInfoDao.remove(id);
    }

    @Override
    public int batchRemove(Long[] ids) {
        return advertiseInfoDao.batchRemove(ids);
    }

    @Override
    public R saveAndVerify(AdvertiseInfoDO saveParam, boolean isSubmit) {
        Long id = saveParam.getId();
        R verifyStatus = this.verifyStatus(id);
        if (verifyStatus != null) {
            return verifyStatus;
        }

        boolean isUpdate = id != null;
        // 获取审批流审批实例
        Long[] approvedPersons = Arrays.stream(saveParam.getApprovedPerson()
                .split(","))
                .filter(StringUtils::isNoneEmpty)
                .map(Long::parseLong)
                .toArray(Long[]::new);

        if (isSubmit) {
            saveParam.setApproveState(ApplyStatusDict.APPLY_APPROVING.getId());
            String processInstanceId = dingdingService.submitApply(approvedPersons, saveParam.getProcessInstanceId());
            saveParam.setProcessInstanceId(processInstanceId);
        } else {
            if (!isUpdate || this.get(id).getApproveState() == ApplyStatusDict.TS.getId()) {
                saveParam.setApproveState(ApplyStatusDict.TS.getId());
            }
        }

        if (isUpdate) {
            advertiseInfoDao.update(saveParam);
        } else {
            // 生成编号 ZPXQ202005110001
            saveParam.setApproveDate(new Date());
            saveParam.setAdvertiseCode(generateCode());
            advertiseInfoDao.save(saveParam);
        }

        id = saveParam.getId();
        // 先删除后增加
        Map<String, Object> deleteParam = Maps.newHashMap();
        deleteParam.put("assocId", id);
        deleteParam.put("assocType", ConstantForHr.ADVERTISE_APPROVE_TARGET);
        userAssocService.removeByAssocIdAndUserId(deleteParam);

        UserAssocDO userAssocDO;
        if (approvedPersons.length > 0) {
            for (Long approvedPerson : approvedPersons) {
                userAssocDO = new UserAssocDO(id, ConstantForHr.ADVERTISE_APPROVE_TARGET, approvedPerson);
                userAssocService.save(userAssocDO);
            }
        }

        Map<String,Object> result = Maps.newHashMap();
        result.put("id",id);
        return R.ok(result);
    }

    private R verifyStatus(Long id) {
        if (id == null) {
            return null;
        }
        AdvertiseInfoDO advertiseInfoDO = this.get(id);
        if (advertiseInfoDO == null) {
            return null;
        }
        long approveState = advertiseInfoDO.getApproveState();
        // 只有暂存和退回才能修改
        return approveState == ApplyStatusDict.TS.getId()
                || approveState == ApplyStatusDict.APPLY_REJECT.getId()
                ? null : R.error(messageSourceHandler.getMessage("hr.advertise.status.operate", null));
    }

    private String generateCode() {
        Map<String, Object> param = Maps.newHashMapWithExpectedSize(3);
        param.put("offset", 0);
        param.put("limit", 1);
        List<AdvertiseInfoDO> list = this.list(param);
        return DateFormatUtil.getWorkOrderNo(ConstantForHr.ADVERTISE_PREFIX, list.size() > 0 ? list.get(0).getAdvertiseCode() : null, 4);
    }

    @Override
    public Map<String, Object> getById(Long id) {
        Map<String,Object> advertiseInfo = advertiseInfoDao.getById(id);
        if (advertiseInfo != null) {
            //获取发送对象
            Map<String,Object> param = Maps.newHashMap();
            param.put("assocId", id);
            param.put("assocType", ConstantForHr.ADVERTISE_APPROVE_TARGET);
            param.put("sort","id");
            param.put("order","ASC");
            List<Map<String, Object>> targetList = userAssocService.list(param);

            Map<String, Object> result = Maps.newHashMap();
            result.put("data", advertiseInfo);
            result.put("approvedPersons",targetList);
            return R.ok(result);
        }
        return R.error();
    }

    @Override
    public Map<String, Object> pageList(AdvertiseInfoPageParam pageParam) {
        Map<String, Object> result = Maps.newHashMap();
        pageParam.setAdvertisePositionName(StringUtils.sqlLike(pageParam.getAdvertisePositionName()));
        String bookmark = pageParam.getBookmark();
        Long userId = ShiroUtils.getUserId();
        List<Long> statusList = Lists.newArrayList();
        if(pageParam.getStatus()!=null){
            statusList.add(pageParam.getStatus());
        }

        // 我发起的
        if("myselfInitiated".equals(bookmark)){
            pageParam.setCreateUserId(userId);
        }

        // 我审批的
        boolean isMyselfApprove = "myselfApprove".equals(bookmark);
        if(isMyselfApprove){
            // 退回与暂存的不显示
            statusList.add(ApplyStatusDict.APPLY_APPROVING.getId());
            statusList.add(ApplyStatusDict.APPLY_COMPLETED.getId());
            pageParam.setApproveUserId(userId);
        }
        // 所有的
//        if("all".equals(bookmark)){
//
//        }
        pageParam.setStatusList(statusList);

        List<Map<String, Object>> data = advertiseInfoDao.pageList(pageParam);
        if (data.size() > 0) {
            if(isMyselfApprove){
                data.forEach(e->{
                    e.put("summary","部门: "+e.getOrDefault("deptName","无")
                            +"\r\n"+"招聘岗位: "+e.getOrDefault("advertisePositionName","无")
                            +"\r\n"+"招聘人数: "+e.getOrDefault("advertiseCounts",0));
                    e.put("title",e.getOrDefault("approvePersonName","")+"招聘需求");
                });
            }
            List<Long> advertiseIdList = data
                    .stream()
                    .map(e -> Long.parseLong(e.get("id").toString()))
                    .collect(Collectors.toList());
            Map<String,Object> param = Maps.newHashMap();
            param.put("advertiseIdList",advertiseIdList);
            List<CandidateInfoDO> candidateInfoList = candidateInfoService.list(param);
            Map<Long, Long> advertiseMap = candidateInfoList
                    .stream()
                    .collect(Collectors.groupingBy(CandidateInfoDO::getAdvertiseId, Collectors.counting()));
            data.forEach(e->{
                Long id = Long.parseLong(e.get("id").toString());
                e.put("resumeCount",advertiseMap.getOrDefault(id, 0L));
            });

            int total = advertiseInfoDao.pageCount(pageParam);
            result.put("data", new DsResultResponse(pageParam.getPageno(), pageParam.getPagesize(), total, data));
        }
        return R.ok(result);
    }

    @Override
    public R batchDelete(List<Long> ids) {
        for (Long id : ids) {
            AdvertiseInfoDO advertiseInfoDO = this.get(id);
            if (advertiseInfoDO == null) {
                return R.error();
            }
            if (!(Objects.equals(advertiseInfoDO.getApproveState(), ApplyStatusDict.TS.getId())
                    || Objects.equals(advertiseInfoDO.getApproveState(), ApplyStatusDict.APPLY_REJECT.getId()))) {
                return R.error(messageSourceHandler.getMessage("common.submit.delete.disabled", null));
            }
        }
        Long[] idsToArray = ids.toArray(new Long[0]);
        this.batchRemove(idsToArray);
        Map<String, Object> deleteParam = Maps.newHashMap();

        deleteParam.put("assocId", idsToArray);
        deleteParam.put("assocType", ConstantForHr.ADVERTISE_APPROVE_TARGET);
        userAssocService.batchRemoveByAssocIdAadType(deleteParam);
        return R.ok();
    }

    @Override
    public Map<String, Object> getJobDescription(Long id) {
        Map<String,Object> advertiseInfo = advertiseInfoDao.getById(id);
        if (advertiseInfo != null) {
            long deptId = Long.parseLong(advertiseInfo.get("deptId").toString());
            Map<String,Object> param = Maps.newHashMap();
            param.put("deptId",deptId);
            // 在职与试用期的员工
            List<Long> stateList = Lists.newArrayList();
            stateList.add(EmployeeStateDict.WORK.getId());
            stateList.add(EmployeeStateDict.PROBATION.getId());
            param.put("stateList", stateList);
            param.put("employeePost",advertiseInfo.getOrDefault("advertisePosition",0));
            List<EmployeeInfoDO> employeeInfoList = employeeInfoService.list(param);
            advertiseInfo.put("nowDeptCount",employeeInfoList.size());
            Map<String, Object> result = Maps.newHashMap();
            result.put("data", advertiseInfo);
            return R.ok(result);
        }
        return R.error();
    }

    @Override
    public R approve(AdvertiseApproveParam saveParam) throws IOException, ParseException {
        AdvertiseInfoDO advertiseInfoDO = get(saveParam.getId());
        if (advertiseInfoDO == null) {
            return R.error();
        }
        Date now = new Date();
        String status = dingdingService.completeApprove(advertiseInfoDO.getProcessInstanceId(),saveParam.getIsApproved()==1,saveParam.getReason());
        boolean isReturn = false;
        boolean isCompleted = false;
        if(Objects.equals(ApplyStatusDict.APPLY_REJECT.getName(),status)){
            isReturn = true;
            advertiseInfoDO.setApproveState(ApplyStatusDict.APPLY_REJECT.getId());
            advertiseInfoDO.setApproveTime(now);
        }
        if(Objects.equals(ApplyStatusDict.APPLY_COMPLETED.getName(),status)){
            isCompleted = true;
            advertiseInfoDO.setApproveState(ApplyStatusDict.APPLY_COMPLETED.getId());
            advertiseInfoDO.setApproveTime(now);
        }
        if (isCompleted||isReturn){
            // 完成
            Long id = advertiseInfoDO.getId();
            // 发送消息
            JSONObject contentDetail = new JSONObject();
            contentDetail.put("id", id);
            // 前端路由
            contentDetail.put("url", "/advertiseManagement/advertiseInfo_add?id=" + id);

            // 若是最后一个流程 通知HR
            Long createBy = advertiseInfoDO.getCreateBy();
            List<Long> usersToLong = Lists.newArrayList();
            usersToLong.add(createBy);

            String content = "单号："+advertiseInfoDO.getAdvertiseCode() + (isCompleted?"的招聘需求已完成":"的招聘需求已被退回");
            // 6： @我的面试日程 的消息类型
            noticeService.saveAndSendSocket("@我的招聘需求", content, id, contentDetail.toString(), 6L, ShiroUtils.getUserId(), usersToLong);
        }

        update(advertiseInfoDO);
        return R.ok();
    }

    @Override
    public R batchClose(List<Long> ids) {
        List<AdvertiseInfoDO> advertiseInfoDOList = Lists.newArrayList();
        for (Long id : ids) {
            AdvertiseInfoDO advertiseInfoDO = this.get(id);
            if (advertiseInfoDO == null) {
                return R.error();
            }
            if (!Objects.equals(advertiseInfoDO.getApproveState(), ApplyStatusDict.APPLY_COMPLETED.getId())) {
                return R.error(messageSourceHandler.getMessage("hr.advertise.isClose", null));
            }
            advertiseInfoDO.setApproveState(ApplyStatusDict.CLOSE.getId());
            advertiseInfoDOList.add(advertiseInfoDO);
        }
        advertiseInfoDao.batchUpdate(advertiseInfoDOList);

        return R.ok();
    }

}
